iT邦幫忙

2023 iThome 鐵人賽

DAY 29
0

週六 have fun 來點 Gatlin 輕快的小品
Yes

Mocking 的核心概念與重要性

測試是確保產品品質關鍵步驟之一。為了確保系統在任何情況下都能正確運行,開發人員會撰寫測試案例來驗證功能與性能。在這個過程中,Mocking 是一個不可或缺的方法。接下來要探討一下 Mocking 的核心概念及在測試中的重要性。

為什麼需要 Mocking?

  • 減少測試的複雜性+隔離單元測試的範疇+避免對外部服務或資料庫的真實依賴

    例如,當我們測試 Service Layer 時,它可能依賴於資料庫、網路等外部資源。Mocking 允許我們創建這些外部資源的 mock 版本,從而減少測試的複雜性和不確定性,確保測試專注在被測模組的邏輯,而不是其依賴的具體實現。此外,依賴於真實環境的測試通常不易重複,因為外部環境可能隨時變化。Mocking 方便我們模擬外部依賴的行為,從而克服這些問題。

Mocking vs Stubbing vs Spying

  • Mocking

    如剛剛所述,Mocking 是模擬模組間互動的過程。當我們說 mock 一個物件時,意味著在創建一個真實物件「假的」或「虛擬」的版本,並控制其行為以符合測試需求。

  • Stubbing

    Stubbing 是 Mocking 的一種。當 stub 一個方法時,我們提供一個預先定義好的回應來模擬真實行為。Stubbing 不關心方法被呼叫的次數或其參數,它只是在被呼叫時回傳一個固定的結果。

  • Spying

    Spying 則與 Mocking 類似,但當 spy 一個物件時,只模擬部分方法的行為,而其他方法則保持原狀。Spying 常用在想檢查或驗證物件的部分行為,同時也想保留其他方法真實行為。

Mocking、Stubbing、和 Spying 是單元測試時常用來模擬和控制物件行為的三種手段。


Mockito 的基本操作

如何創建 Mock 物件

在 Mockito 中,創建一個 Mock 物件非常直覺。假設有一個 PaymentService 並在測試裡模擬它的行為:

PaymentService paymentServiceMock = Mockito.mock(PaymentService.class);

如何使用 Mock 物件進行測試

當 Mock 物件建立後可以去定義它的行為。例如,可以指定當呼叫 paymentServiceMock.processPayment(any()) 時,return 特定值或觸發特定行為:

Mockito.when(paymentServiceMock.processPayment(any(Payment.class))).thenReturn(true);

any(Payment.class) 是一個 Argument Matcher。

驗證 Mock 物件的行為

Mockito.verify(paymentServiceMock).processPayment(any(Payment.class));

使用 Argument Matchers

Argument Matchers 是在模擬方法行為時,對輸入參數的預期值進行彈性的定義。例如:

Mockito.when(paymentServiceMock.processPayment(any(Payment.class))).thenReturn(true);

在這裡 any(Payment.class) 是一個 Argument Matcher,表示我們不關心實際傳入 processPayment 方法的具體 Payment 物件是什麼。

使用 Annotations

Mockito 提供一系列的註解:

@RunWith(MockitoJUnitRunner.class)
public class PaymentServiceTest {

    @Mock
    PaymentService paymentServiceMock;

    @InjectMocks
    OrderService orderService;

    // ... 其他測試
}

@Mock 註解是用來建立一個 PaymentService 的 Mock 物件,而 @InjectMocks 則將所有的 Mock 物件自動注入到 OrderService 中。

返回預期的結果

可以模擬方法呼叫後的返回值,也可以模擬方法被呼叫時時拋出 exception:

Mockito.when(paymentServiceMock.processPayment(any(Payment.class))).thenThrow(new PaymentException());

上一篇
Day 28 - TDD 測試驅動開發
下一篇
Day 30 - Recap
系列文
Spring Boot 三十天挑戰賽30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言